using System;
using System.Configuration;
using System.Configuration.Provider;
using System.Collections.Generic;
using System.Text;
using System.Web.Security;

using Dunnry.Security;
using System.Collections.Specialized;

namespace Dunnry.Web.Security
{
    class ActiveDirectoryRoleProvider : RoleProvider
    {
        RoleManager _roleManager;
        string _adsPath;

        public override void Initialize(string name, NameValueCollection config)
        {
            if (config == null)
                throw new ArgumentNullException("config");

            if (string.IsNullOrEmpty(name))
                name = "ActiveDirectoryRoleProvider";

            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "ActiveDirectoryRoleProvider");
            }

            base.Initialize(name, config);

            // we need the connectionString and it must have a server
            if (String.IsNullOrEmpty(config["connectionStringName"]))
                throw new ProviderException("connectionStringName must be configured");

            string connStringName = config["connectionStringName"];
            config.Remove("connectionStringName");

            #region Credential Setup
            //  For now and until I determine a good way to handle it, I am only supporting
            //  a single security model - namely a trusted subsystem model.  This means that
            //  for both AD and ADAM, the app pool must have permission.

            //            string username = config["connectionUsername"];
            //            config.Remove("connectionUsername");
            //
            //            string password = config["connectionPassword"];
            //            config.Remove("connectionPassword");

            //            string protectLevel = config["connectionProtection"];
            //            Dunnry.DirectoryServices.ConnectionProtection protect = Dunnry.DirectoryServices.ConnectionProtection.Secure;

            //            if (!String.IsNullOrEmpty(username))
            //                protect = Dunnry.DirectoryServices.ConnectionProtection.None; 
            #endregion

            if (ConfigurationManager.ConnectionStrings[connStringName] == null)
                throw new ProviderException("Cannot find connectionStringName in connectionStrings");

            // this will be the basis for all of what we do
            _adsPath = ConfigurationManager.ConnectionStrings[connStringName].ConnectionString;

            if (!_adsPath.ToUpperInvariant().StartsWith("LDAP://", StringComparison.OrdinalIgnoreCase))
                throw new ProviderException("Only LDAP provider is supported");

            try
            {
                _roleManager = new RoleManager(_adsPath);
            }
            catch (Exception ex)
            {
                throw new ProviderException("Error Configuring Provider", ex);
            }

            // check for unknown config values
            if (config.Count > 0)
            {
                string unknownValue = config.GetKey(0);

                if (!string.IsNullOrEmpty(unknownValue))
                    throw new ProviderException("Unrecognized Configuration Attribute: " + unknownValue);
            }

        }

        public override string[] GetRolesForUser(string username)
        {
            return _roleManager.GetRolesForUser(username);
        }

        #region Not Implemented
        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override string ApplicationName
        {
            get
            {
                throw new Exception("The method or operation is not implemented.");
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }

        public override void CreateRole(string roleName)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override string[] GetAllRoles()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override string[] GetUsersInRole(string roleName)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override bool RoleExists(string roleName)
        {
            throw new Exception("The method or operation is not implemented.");
        }
        #endregion
    }
}
